Baeldung Pro – Ops – NPI EA (cat = Baeldung on Ops)
announcement - icon

Learn through the super-clean Baeldung Pro experience:

>> Membership and Baeldung Pro.

No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.

1. Overview

In Docker, developers can build, deploy, and test applications by packaging them in a container along with all of their dependencies. Docker Compose is an essential tool for managing many containers using services.

In this tutorial, we’ll understand how to execute multiple commands in a Docker container, managed using Docker Compose. Additionally, we’ll explore different ways to run multiple commands in the Docker container.

2. Running Single Command

Docker Compose enables us to execute commands inside a Docker container. We can set any command to run during the container startup via the command instruction.

Let’s take a look at a docker-compose.yml, which runs a simple command inside a container:

version: "3"
services:
 server:
   image: alpine
   command: sh -c "echo "baeldung""

In the above docker-compose.yml file, we execute a single echo command inside the alpine Docker image.

3. Running Multiple Commands

Of course, we can use Docker Compose to manage more than one application by creating services in the docker-compose.yml file. Let’s take a look at how to run multiple commands.

3.1. Using the && Operator

We start by creating a simple docker-compose.yml file to demonstrate how the Docker Compose configuration runs more than one command:

version: "3"
services:
 server:
   image: alpine
   command: sh -c "echo "baeldung" && echo "docker" "

Here, we used alpine as the base image for the Docker container. Notably, we execute two commands in the last line: echo baeldung and echo docker, split by the && operator.

To demonstrate the result, let’s run this image using the docker-compose up command:

$ docker-compose up
Creating dockercompose_server_1 ... done
Attaching to dockercompose_server_1
server_1  | baeldung
server_1  | docker
dockercompose_server_1 exited with code 0

Here, the output of both echo statements goes to stdout.

3.2. Using the | Operator

We can also use the | operator to run multiple commands in Docker Compose. The syntax of the | operator is a bit different from the && operator.

To illustrate how the | operator works, let’s update the docker-compose.yml:

version: "3"
services:
 server:
   image: alpine
   command:
      - /bin/sh
      - -c
      - |
        echo "baeldung"
        echo "docker"

Everything is the same except for the command instruction. Here, we added the commands on separate lines. Thus, this approach is recommended as it keeps the YAML file neater since each command is on a separate line.

Let’s again run the Docker container with the docker-compose up command:

$ docker-compose up
Creating dockercompose_server_1 ... done
Attaching to dockercompose_server_1
server_1  | baeldung
server_1  | docker
dockercompose_server_1 exited with code 0

As we can see from the above output, both commands run one by one.

3.3. Executing Commands From a Shell Script

When we have a series of commands that we need to execute in a specific order or want to reuse across multiple services, a shell script provides a clean and organized solution.

We can bundle all the commands into a single script, include it in the Docker image, and then execute it using Docker Compose.

Let’s say we have a script called script.sh:

$ cat script.sh
#!/bin/sh

echo "Setting up the environment..."
mkdir -p /app/data
cp /tmp/config.ini /app/config/
echo "Starting the application..."
python /app/main.py

Thus, we can include this script in the Dockerfile and make it executable:

$ cat Dockerfile
FROM python:3.9-slim-buster

WORKDIR /app
COPY . .
COPY script.sh /app/script.sh
RUN chmod +x /app/script.sh

CMD ["/app/script.sh"]

Finally, in the docker-compose.yml, we reference the script as the command for the service:

$ cat docker-compose.yml

version: '3'
services:
  myapp:
    build: .
    command: /app/script.sh

Now, when we run docker-compose up, Docker Compose executes script.sh and runs all the commands within it sequentially.

3.4. Using a .bat File

While shell scripts are great for Linux-based environments, we need a different approach when working with Windows containers.

In these cases, we can use a .bat file to bundle commands. It’s essentially the Windows equivalent of a shell script.

For example, if we have a .bat file named setup.bat:

@echo off
echo "Setting up the Windows environment..."
mkdir C:\app\data
copy C:\temp\config.ini C:\app\config\
echo "Starting the application..."
C:\app\myapp.exe

We can include this file in the Docker image during the build process, similar to how we included shell scripts:

FROM mcr.microsoft.com/windows/servercore:ltsc2022

WORKDIR /app
COPY . .
COPY setup.bat C:\app\setup.bat

CMD ["C:\\app\\setup.bat"]

In the docker-compose.yml, we then reference the .bat file as the command for the service:

version: '3'
services:
  myapp:
    build: .
    command: C:\app\setup.bat

Therefore, when we run docker-compose up, Docker Compose executes the setup.bat file.

4. Benefits of Executing Multiple Commands in Docker Compose

Executing multiple commands within a Docker Compose file offers several advantages:

  • Simplified container startup: streamlines the container startup process by bundling commands, thereby reducing manual effort and potential errors
  • Customized container behavior: helpful when running setup or cleanup scripts alongside the main application
  • Enhanced debugging: multiple commands enhance debugging by enabling us to gather logs or run tests within the container
  • Reduced resource consumption: can reduce resource consumption by consolidating services within a single container
  • Streamlined development: automates tasks like database migrations and testing, improving development efficiency

In conclusion, executing multiple commands in Docker Compose empowers us with greater control and flexibility in managing containerized applications.

5. Conclusion

In this article, we explored various methods for executing multiple commands in a Docker Compose environment. We started with simpler techniques using the && and | operators, then moved on to more organized approaches with shell scripts and batch files.